#ifndef THINK_THINK_CONSOLE_OUTPUT_ASK_H
#define THINK_THINK_CONSOLE_OUTPUT_ASK_H

static char* think_console_output_ask =
	"\n"
	"// +----------------------------------------------------------------------\n"
	"// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n"
	"// +----------------------------------------------------------------------\n"
	"// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.\n"
	"// +----------------------------------------------------------------------\n"
	"// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n"
	"// +----------------------------------------------------------------------\n"
	"// | Author: yunwuxin <448901948@qq.com>\n"
	"// +----------------------------------------------------------------------\n"
	"\n"
	"namespace think\\console\\output;\n"
	"\n"
	"use think\\console\\Input;\n"
	"use think\\console\\Output;\n"
	"use think\\console\\output\\question\\Choice;\n"
	"use think\\console\\output\\question\\Confirmation;\n"
	"\n"
	"class Ask\n"
	"{\n"
	"    private static $stty;\n"
	"\n"
	"    private static $shell;\n"
	"\n"
	"    /** @var  Input */\n"
	"    protected $input;\n"
	"\n"
	"    /** @var  Output */\n"
	"    protected $output;\n"
	"\n"
	"    /** @var  Question */\n"
	"    protected $question;\n"
	"\n"
	"    public function __construct(Input $input, Output $output, Question $question)\n"
	"    {\n"
	"        $this->input    = $input;\n"
	"        $this->output   = $output;\n"
	"        $this->question = $question;\n"
	"    }\n"
	"\n"
	"    public function run()\n"
	"    {\n"
	"        if (!$this->input->isInteractive()) {\n"
	"            return $this->question->getDefault();\n"
	"        }\n"
	"\n"
	"        if (!$this->question->getValidator()) {\n"
	"            return $this->doAsk();\n"
	"        }\n"
	"\n"
	"        $that = $this;\n"
	"\n"
	"        $interviewer = function () use ($that) {\n"
	"            return $that->doAsk();\n"
	"        };\n"
	"\n"
	"        return $this->validateAttempts($interviewer);\n"
	"    }\n"
	"\n"
	"    protected function doAsk()\n"
	"    {\n"
	"        $this->writePrompt();\n"
	"\n"
	"        $inputStream  = STDIN;\n"
	"        $autocomplete = $this->question->getAutocompleterValues();\n"
	"\n"
	"        if (null === $autocomplete || !$this->hasSttyAvailable()) {\n"
	"            $ret = false;\n"
	"            if ($this->question->isHidden()) {\n"
	"                try {\n"
	"                    $ret = trim($this->getHiddenResponse($inputStream));\n"
	"                } catch (\\RuntimeException $e) {\n"
	"                    if (!$this->question->isHiddenFallback()) {\n"
	"                        throw $e;\n"
	"                    }\n"
	"                }\n"
	"            }\n"
	"\n"
	"            if (false === $ret) {\n"
	"                $ret = fgets($inputStream, 4096);\n"
	"                if (false === $ret) {\n"
	"                    throw new \\RuntimeException(\'Aborted\');\n"
	"                }\n"
	"                $ret = trim($ret);\n"
	"            }\n"
	"        } else {\n"
	"            $ret = trim($this->autocomplete($inputStream));\n"
	"        }\n"
	"\n"
	"        $ret = strlen($ret) > 0 ? $ret : $this->question->getDefault();\n"
	"\n"
	"        if ($normalizer = $this->question->getNormalizer()) {\n"
	"            return $normalizer($ret);\n"
	"        }\n"
	"\n"
	"        return $ret;\n"
	"    }\n"
	"\n"
	"    private function autocomplete($inputStream)\n"
	"    {\n"
	"        $autocomplete = $this->question->getAutocompleterValues();\n"
	"        $ret          = \'\';\n"
	"\n"
	"        $i          = 0;\n"
	"        $ofs        = -1;\n"
	"        $matches    = $autocomplete;\n"
	"        $numMatches = count($matches);\n"
	"\n"
	"        $sttyMode = shell_exec(\'stty -g\');\n"
	"\n"
	"        shell_exec(\'stty -icanon -echo\');\n"
	"\n"
	"        while (!feof($inputStream)) {\n"
	"            $c = fread($inputStream, 1);\n"
	"\n"
	"            if (\"\\177\" === $c) {\n"
	"                if (0 === $numMatches && 0 !== $i) {\n"
	"                    --$i;\n"
	"                    $this->output->write(\"\\033[1D\");\n"
	"                }\n"
	"\n"
	"                if ($i === 0) {\n"
	"                    $ofs        = -1;\n"
	"                    $matches    = $autocomplete;\n"
	"                    $numMatches = count($matches);\n"
	"                } else {\n"
	"                    $numMatches = 0;\n"
	"                }\n"
	"\n"
	"                $ret = substr($ret, 0, $i);\n"
	"            } elseif (\"\\033\" === $c) {\n"
	"                $c .= fread($inputStream, 2);\n"
	"\n"
	"                if (isset($c[2]) && (\'A\' === $c[2] || \'B\' === $c[2])) {\n"
	"                    if (\'A\' === $c[2] && -1 === $ofs) {\n"
	"                        $ofs = 0;\n"
	"                    }\n"
	"\n"
	"                    if (0 === $numMatches) {\n"
	"                        continue;\n"
	"                    }\n"
	"\n"
	"                    $ofs += (\'A\' === $c[2]) ? -1 : 1;\n"
	"                    $ofs = ($numMatches + $ofs) % $numMatches;\n"
	"                }\n"
	"            } elseif (ord($c) < 32) {\n"
	"                if (\"\\t\" === $c || \"\\n\" === $c) {\n"
	"                    if ($numMatches > 0 && -1 !== $ofs) {\n"
	"                        $ret = $matches[$ofs];\n"
	"                        $this->output->write(substr($ret, $i));\n"
	"                        $i = strlen($ret);\n"
	"                    }\n"
	"\n"
	"                    if (\"\\n\" === $c) {\n"
	"                        $this->output->write($c);\n"
	"                        break;\n"
	"                    }\n"
	"\n"
	"                    $numMatches = 0;\n"
	"                }\n"
	"\n"
	"                continue;\n"
	"            } else {\n"
	"                $this->output->write($c);\n"
	"                $ret .= $c;\n"
	"                ++$i;\n"
	"\n"
	"                $numMatches = 0;\n"
	"                $ofs        = 0;\n"
	"\n"
	"                foreach ($autocomplete as $value) {\n"
	"                    if (0 === strpos($value, $ret) && $i !== strlen($value)) {\n"
	"                        $matches[$numMatches++] = $value;\n"
	"                    }\n"
	"                }\n"
	"            }\n"
	"\n"
	"            $this->output->write(\"\\033[K\");\n"
	"\n"
	"            if ($numMatches > 0 && -1 !== $ofs) {\n"
	"                $this->output->write(\"\\0337\");\n"
	"                $this->output->highlight(substr($matches[$ofs], $i));\n"
	"                $this->output->write(\"\\0338\");\n"
	"            }\n"
	"        }\n"
	"\n"
	"        shell_exec(sprintf(\'stty %s\', $sttyMode));\n"
	"\n"
	"        return $ret;\n"
	"    }\n"
	"\n"
	"    protected function getHiddenResponse($inputStream)\n"
	"    {\n"
	"        if (\'\\\\\' === DIRECTORY_SEPARATOR) {\n"
	"            $exe = __DIR__ . \'/../bin/hiddeninput.exe\';\n"
	"\n"
	"            $value = rtrim(shell_exec($exe));\n"
	"            $this->output->writeln(\'\');\n"
	"\n"
	"            if (isset($tmpExe)) {\n"
	"                unlink($tmpExe);\n"
	"            }\n"
	"\n"
	"            return $value;\n"
	"        }\n"
	"\n"
	"        if ($this->hasSttyAvailable()) {\n"
	"            $sttyMode = shell_exec(\'stty -g\');\n"
	"\n"
	"            shell_exec(\'stty -echo\');\n"
	"            $value = fgets($inputStream, 4096);\n"
	"            shell_exec(sprintf(\'stty %s\', $sttyMode));\n"
	"\n"
	"            if (false === $value) {\n"
	"                throw new \\RuntimeException(\'Aborted\');\n"
	"            }\n"
	"\n"
	"            $value = trim($value);\n"
	"            $this->output->writeln(\'\');\n"
	"\n"
	"            return $value;\n"
	"        }\n"
	"\n"
	"        if (false !== $shell = $this->getShell()) {\n"
	"            $readCmd = $shell === \'csh\' ? \'set mypassword = $<\' : \'read -r mypassword\';\n"
	"            $command = sprintf(\"/usr/bin/env %s -c \'stty -echo; %s; stty echo; echo \\$mypassword\'\", $shell, $readCmd);\n"
	"            $value   = rtrim(shell_exec($command));\n"
	"            $this->output->writeln(\'\');\n"
	"\n"
	"            return $value;\n"
	"        }\n"
	"\n"
	"        throw new \\RuntimeException(\'Unable to hide the response.\');\n"
	"    }\n"
	"\n"
	"    protected function validateAttempts($interviewer)\n"
	"    {\n"
	"        /** @var \\Exception $error */\n"
	"        $error    = null;\n"
	"        $attempts = $this->question->getMaxAttempts();\n"
	"        while (null === $attempts || $attempts--) {\n"
	"            if (null !== $error) {\n"
	"                $this->output->error($error->getMessage());\n"
	"            }\n"
	"\n"
	"            try {\n"
	"                return call_user_func($this->question->getValidator(), $interviewer());\n"
	"            } catch (\\Exception $error) {\n"
	"            }\n"
	"        }\n"
	"\n"
	"        throw $error;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 显示问题的提示信息\n"
	"     */\n"
	"    protected function writePrompt()\n"
	"    {\n"
	"        $text    = $this->question->getQuestion();\n"
	"        $default = $this->question->getDefault();\n"
	"\n"
	"        switch (true) {\n"
	"            case null === $default:\n"
	"                $text = sprintf(\' <info>%s</info>:\', $text);\n"
	"\n"
	"                break;\n"
	"\n"
	"            case $this->question instanceof Confirmation:\n"
	"                $text = sprintf(\' <info>%s (yes/no)</info> [<comment>%s</comment>]:\', $text, $default ? \'yes\' : \'no\');\n"
	"\n"
	"                break;\n"
	"\n"
	"            case $this->question instanceof Choice && $this->question->isMultiselect():\n"
	"                $choices = $this->question->getChoices();\n"
	"                $default = explode(\',\', $default);\n"
	"\n"
	"                foreach ($default as $key => $value) {\n"
	"                    $default[$key] = $choices[trim($value)];\n"
	"                }\n"
	"\n"
	"                $text = sprintf(\' <info>%s</info> [<comment>%s</comment>]:\', $text, implode(\', \', $default));\n"
	"\n"
	"                break;\n"
	"\n"
	"            case $this->question instanceof Choice:\n"
	"                $choices = $this->question->getChoices();\n"
	"                $text    = sprintf(\' <info>%s</info> [<comment>%s</comment>]:\', $text, $choices[$default]);\n"
	"\n"
	"                break;\n"
	"\n"
	"            default:\n"
	"                $text = sprintf(\' <info>%s</info> [<comment>%s</comment>]:\', $text, $default);\n"
	"        }\n"
	"\n"
	"        $this->output->writeln($text);\n"
	"\n"
	"        if ($this->question instanceof Choice) {\n"
	"            $width = max(array_map(\'strlen\', array_keys($this->question->getChoices())));\n"
	"\n"
	"            foreach ($this->question->getChoices() as $key => $value) {\n"
	"                $this->output->writeln(sprintf(\"  [<comment>%-${width}s</comment>] %s\", $key, $value));\n"
	"            }\n"
	"        }\n"
	"\n"
	"        $this->output->write(\' > \');\n"
	"    }\n"
	"\n"
	"    private function getShell()\n"
	"    {\n"
	"        if (null !== self::$shell) {\n"
	"            return self::$shell;\n"
	"        }\n"
	"\n"
	"        self::$shell = false;\n"
	"\n"
	"        if (file_exists(\'/usr/bin/env\')) {\n"
	"            $test = \"/usr/bin/env %s -c \'echo OK\' 2> /dev/null\";\n"
	"            foreach ([\'bash\', \'zsh\', \'ksh\', \'csh\'] as $sh) {\n"
	"                if (\'OK\' === rtrim(shell_exec(sprintf($test, $sh)))) {\n"
	"                    self::$shell = $sh;\n"
	"                    break;\n"
	"                }\n"
	"            }\n"
	"        }\n"
	"\n"
	"        return self::$shell;\n"
	"    }\n"
	"\n"
	"    private function hasSttyAvailable()\n"
	"    {\n"
	"        if (null !== self::$stty) {\n"
	"            return self::$stty;\n"
	"        }\n"
	"\n"
	"        exec(\'stty 2>&1\', $output, $exitcode);\n"
	"\n"
	"        return self::$stty = $exitcode === 0;\n"
	"    }\n"
	"}\n"
	"\n"
;
#endif